/******************************************************************************
Project    : Real time rtsp server library base on live555
*******************************************************************************
File Name    :  <ADtsRTimeFramedSource.cpp>:  adts real time framed source source file
Module Name  :  
Description  :  None
History      :
 No.   Ver.     Date        Designed by  Comment
-----+--------+----------+------------+---------------------------------------
 001   0.00.01  05/25/2015  <3G@LIURENHUA>   <adts real time framed source source file>
*******************************************************************************/
#include "AdtsRTimeFramedSource.h"

/******************************************************************************
  static global array define
 ******************************************************************************/
static u_int32_t const samplingFrequencyTable[16] = {
	96000, 88200, 64000, 48000,
	44100, 32000, 24000, 22050,
	16000, 12000, 11025, 8000,
	7350, 0, 0, 0
};

/******************************************************************************
  class functions define
 ******************************************************************************/
ADtsRTimeFramedSource* 
	ADtsRTimeFramedSource::createNew(
							UsageEnvironment & env,
#ifdef LOCAL_SOCK_INPUT
							const char  *pcIdentity,
#endif /* LOCAL_SOCK_INPUT */
							const CH_CFG_et eChCfg,
							const FS_IDX_et eFsIdx,
							const PROFILE_et eProfile,
#ifdef LOCAL_SOCK_INPUT
							const u_int32_t unSBufSize,
							const u_int32_t unRBufSize
#else
							queue_t *pstQue
#endif /* LOCAL_SOCK_INPUT */
							)
{
	return new ADtsRTimeFramedSource(env, 
#ifdef LOCAL_SOCK_INPUT
							pcIdentity,
#endif /* LOCAL_SOCK_INPUT */
							eChCfg, 
							eFsIdx, 
							eProfile,
#ifdef LOCAL_SOCK_INPUT
							unSBufSize, 
							unRBufSize
#else
							pstQue
#endif /* LOCAL_SOCK_INPUT */
							);
}

ADtsRTimeFramedSource::ADtsRTimeFramedSource(
							UsageEnvironment & env,
#ifdef LOCAL_SOCK_INPUT
							const char  *pcIdentity,
#endif /* LOCAL_SOCK_INPUT */
							const CH_CFG_et eChCfg,
							const FS_IDX_et eFsIdx,
							const PROFILE_et eProfile,
#ifdef LOCAL_SOCK_INPUT
							const u_int32_t unSBufSize,
							const u_int32_t unRBufSize
#else
							queue_t *pstQue
#endif /* LOCAL_SOCK_INPUT */
							) : FramedSource(env)
{
#ifdef LOCAL_SOCK_INPUT
	/* Clear class members */
	pstServer = NULL;
#else
	m_que = pstQue;
#endif /* LOCAL_SOCK_INPUT */

	/* Get sampling frequency with fs index */
	m_unFs = samplingFrequencyTable[(int)eFsIdx];
	if( (0 == m_unFs) ){return;}

	/* Get channel number with channel config */
	m_ucCh = ((int)eChCfg == 0) ? 2 : (int)eChCfg;
	m_unUsecLeft = 0;

#ifdef LOCAL_SOCK_INPUT
	/* Initialize local udp socket with identity */
	if( (LSOCK_ERR_NOERR != 
		eInitLocalUdpSocket(&pstServer, pcIdentity, 
		LSOCK_TYPE_S, unSBufSize, unRBufSize)) ){
		printf("[%s]initialize local udp socket failed\n",
			__func__);
		return;
	}
#endif /* LOCAL_SOCK_INPUT */
	
	/* Calculate microsecond each frame */
 	m_unUsecPerFrm = (1024 * 1000000) / m_unFs;
	m_unUsecRemain = (1024 * 1000000) % m_unFs;
	
	{/* Construct the 'AudioSpecificConfig' */
		unsigned char audioSpecificConfig[2];
	  	u_int8_t const audioObjectType = (int)eProfile+1;
	  	audioSpecificConfig[0] = 
			(audioObjectType<<3) | ((int)eFsIdx >> 1);
	  	audioSpecificConfig[1] = 
			((int)eFsIdx << 7) | ((int)eChCfg << 3);
	  	snprintf(m_cConfigStr, sizeof(m_cConfigStr), 
			"%02X%02x", audioSpecificConfig[0], 
			audioSpecificConfig[1]);
	}
}

ADtsRTimeFramedSource::~ADtsRTimeFramedSource()
{
#ifdef LOCAL_SOCK_INPUT
	if( (NULL != pstServer) ){
		vDInitLocalUdpSocket(pstServer);
		pstServer = NULL;
	}
#endif /* LOCAL_SOCK_INPUT */
}

void ADtsRTimeFramedSource::doGetNextFrame()
{
	/* Initialize require read size */
	int read = fMaxSize;
	fFrameSize = 0;
	
#ifdef FRAME_DEBUG
	printf("-----enter [%s][%d]-----\n", __func__, read);
#endif /* FRAME_RTP_DEBUG */

#ifdef LOCAL_SOCK_INPUT
	/* Receive encode data from encoder */
	if( (LSOCK_ERR_NOERR == 
		eRecvDataByLUdpSock(pstServer, fTo, &read)) ){
		if( (read <= 0) ){
			printf("[%s]no data = %d\n", __func__, read);
			fNumTruncatedBytes = 0;
			return;
		}
	}else{
		printf("[%s]receive data failed from local socket\n", 
			__func__);
		fNumTruncatedBytes = 0;
		return;
	}
#else
	AVPacket *pkt =  (AVPacket *)q_pop_tail(m_que);
	if( (NULL != pkt) ){
		if( (pkt->size <= read) ){
			fNumTruncatedBytes = 0;
			read = pkt->size;
		}else{
			fNumTruncatedBytes = pkt->size - read;
		}
		if( (pkt->data != NULL) ){
			memcpy(fTo, pkt->data, read);
			free(pkt->data);
		}
		free(pkt);
	}else{
		fNumTruncatedBytes = 0;
		return;
	}
#endif /* LOCAL_SOCK_INPUT */

#ifdef LOCAL_SOCK_INPUT
	fNumTruncatedBytes = 0;
#endif /* LOCAL_SOCK_INPUT */
	fFrameSize = read;
	if ( (fFrameSize == 0) ) {
		handleClosure();
    		return;
  	}
	
	/* Update presentation time with frame rate */
	if ( (fPresentationTime.tv_sec == 0 
	 	&& fPresentationTime.tv_usec == 0) ) {
	 	/* This is the first frame, so use the current time */
	 	gettimeofday(&fPresentationTime, NULL);
	}else{
		u_int32_t uSeconds = 
			fPresentationTime.tv_usec+m_unUsecPerFrm;
		m_unUsecLeft += m_unUsecRemain;
		if( (m_unUsecLeft >= m_unFs) ){
			m_unUsecLeft -= m_unFs;
			uSeconds += 1;
		}
		fPresentationTime.tv_sec += (uSeconds / 1000000);
		fPresentationTime.tv_usec = (uSeconds %1000000);
	}
	fDurationInMicroseconds = (1024 * 1000000.0) / m_unFs;
	
  	nextTask() = 
		envir().taskScheduler().scheduleDelayedTask(0,
		(TaskFunc*)FramedSource::afterGetting, this);
}
